#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;
const int size = 1024;
const int argvsize = 64;
const int envnum = 64;
//全局的命令行参数表
char* argv[argvsize];
int gregc = 0;

//我的系统的环境变量
char* genv[envnum];

//全局的当前shell工作路径
char pwd[size]; 
char pwdenv[size];

string getuser()//获取用户名
{
    string name = getenv("USER");
    return name.empty() ? "null" : name;
}
string gethost()//获取主机名
{
    string name = getenv("HOSTNAME");
    return name.empty() ? "null" : name;
}
string getpwd()//获取当前路径
{
    //string name = getenv("PWD");
    if(getcwd(pwd,sizeof(pwd)) == nullptr) return "null";
    //更新环境变量
    snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);
    putenv(pwdenv);

    //return name.empty() ? "null" : name;
    return pwd;
}

string getprint()
{
    char comm[size];
    snprintf(comm,size,"[%s@%s %s]# ",
            getuser().c_str(),gethost().c_str(),getpwd().c_str());
    return comm;
}
void printcomm()//1.命令提示符
{
    printf("%s",getprint().c_str());
    fflush(stdout);//刷新缓冲区
}

bool getcommand(char command_buff[],int size)
{
    char* res = fgets(command_buff,size,stdin);//标准输入，获取字符串，放到数组里
    if(!res)
    {
        return false;
    }
    command_buff[strlen(command_buff)-1] = 0;
    if(strlen(command_buff) == 0) return false;
    return true;
}

bool parcomm(char getcommand_buff[],int len)
{
    //将参数表清除
    memset(argv,0,sizeof(argv));
    gregc = 0;
    const char *sep = " ";
    //"ls -a -l"
    //首次将ls提取出来
    argv[gregc++] = strtok(getcommand_buff,sep);
    //继续往后分割 
    while(argv[gregc++] = strtok(nullptr,sep));
    gregc--;
   return 1;
}

void debug()
{
    printf("gregc:%d \n",gregc);
    int i=0;
    for(i;argv[i];i++)
    {
        printf("argv[%d]:%s \n",i,argv[i]);
    }
}
bool  execomm()
{
    //让子进程执行
    pid_t id = fork();
    if(id < 0) return false;
    if(id == 0)
    {
        //子进程
        //执行命令
        execvp(argv[0],argv);
        //退出
        exit(1);
    }
    int stat = 0;
    pid_t rid = waitpid(id,&stat,0);
    if(rid > 0)
    {
        //null
    }
    return false;
}
void addenv(const char* item)
{
    int i=0;
    while(argv[i])//找结尾
    {
        i++;
    }
    genv[i] = (char*)malloc(strlen(item)+1);//开辟一块空间
    strncpy(genv[i],item,strlen(item)+1);//导入到argv里
    genv[++i] = nullptr;//结尾置为nullptr
}
//shell自己执行命令，本质是shell调用自己的函数
bool check()
{
    //判断是不是等于cd命令
    if(strcmp(argv[0],"cd") == 0)
    {
        //内键命令
        if(gregc == 2)//等于2,说明cd后面根了路径和..
        {
             chdir(argv[1]);
        }

        return true;
    }
    else if(strcmp(argv[0],"export")==0)
    {
        if(gregc == 2)
        {
            addenv(argv[1]);
        }
        return true;
    }
    else if(strcmp(argv[0],"env")==0)
    {
        //打印自己的环境变量表
        int i=0;
        for(i;genv[i];i++)
        {
            printf("%s\n",genv[i]);
        }

        return true;
    }
    return false;
}

//从shell获取环境变量
void linenv()
{
    extern char** environ;
    int i=0;
    while(environ[i])
    {
        //给genv开辟一块空间
        genv[i] = (char*)malloc(strlen(environ[i])+1);
        //将环境变量拷贝给genv
        strncpy(genv[i],environ[i],strlen(environ[i])+1);
        i++;
    }
    genv[i]=nullptr;
}

int main()
{
    linenv();
    char getcommand_buff[size];
    while(true)
    {
       printcomm(); //1.命令提示符
        //2.获取用户命令
        if(!getcommand(getcommand_buff,size))
        {
            continue;//重新获取
        }
        //printf("%s",getcommand_buff);
        //3.分析命令
        //ls 
        //"ls -a -l" -> "ls" "-a" "-l"
        parcomm(getcommand_buff,strlen(getcommand_buff));
        //debug();
       // if(check())
       // {
       //     continue;
       // }
        //4.执行命令
        execomm();
    }
    return 0;
}
